#ifndef SOBJC_COMMONS_TYPE_H
#define SOBJC_COMMONS_TYPE_H

#include <sobjc-commons/str_list.h>

typedef struct objc_type            objc_type, *objc_type_t;
typedef struct objc_type_encoding   objc_type_encoding, *objc_type_encoding_t;

OBJC_EXPORT void objc_free_type(objc_type_t);

OBJC_DEF_LIST(type_list, objc_type_t, objc_type_t,
              OBJC_LIST_NO_INIT,
              objc_free_type)

typedef enum OBJC_TYPE_CODE_TYPE {
  OBJC_TYPE_PRIM_CODE_TYPE,
  OBJC_TYPE_ARRAY_CODE_TYPE,
  OBJC_TYPE_STRUCT_CODE_TYPE,
  OBJC_TYPE_BITFIELD_CODE_TYPE,
  OBJC_TYPE_UNION_CODE_TYPE
} OBJC_TYPE_CODE_TYPE;

typedef enum OBJC_TYPE_PRIM_TYPE {
  OBJC_TYPE_CHAR_PRIM_TYPE,
  OBJC_TYPE_UCHAR_PRIM_TYPE,
  OBJC_TYPE_SHORT_PRIM_TYPE,
  OBJC_TYPE_USHORT_PRIM_TYPE,
  OBJC_TYPE_INT_PRIM_TYPE,
  OBJC_TYPE_UINT_PRIM_TYPE,
  OBJC_TYPE_LONG_PRIM_TYPE,
  OBJC_TYPE_ULONG_PRIM_TYPE,
#ifdef HAVE_LONG_LONG
  OBJC_TYPE_LONGLONG_PRIM_TYPE,
  OBJC_TYPE_ULONGLONG_PRIM_TYPE,
#endif
  OBJC_TYPE_FLOAT_PRIM_TYPE,
  OBJC_TYPE_DOUBLE_PRIM_TYPE,
  OBJC_TYPE_BOOL_PRIM_TYPE,
  OBJC_TYPE_VOID_PRIM_TYPE,
  OBJC_TYPE_STR_PRIM_TYPE,
  OBJC_TYPE_ID_PRIM_TYPE,
  OBJC_TYPE_CLASS_PRIM_TYPE,
  OBJC_TYPE_SEL_PRIM_TYPE,
  OBJC_TYPE_UNKNOWN_PRIM_TYPE
} OBJC_TYPE_PRIM_TYPE;

struct objc_type {
  OBJC_TYPE_CODE_TYPE code_type;
  int nptrs;
  unsigned int quals;
  union {
    OBJC_TYPE_PRIM_TYPE prim;
    struct {
      objc_type_t elem;
      int nelems;
    } array;
    struct {
      char *name;
      objc_type_list_t mems;
    } su; /* struct or union */
    int nbits;
  } body;
};

struct objc_type_encoding {
  char *full_code;
  size_t ncodes;
  objc_str_list_t codes;
  objc_type_list_t types;
};

#define OBJC_TYPE_CONST_QUAL        (1<<1)
#define OBJC_TYPE_IN_QUAL           (1<<2)
#define OBJC_TYPE_INOUT_QUAL        (1<<3)
#define OBJC_TYPE_OUT_QUAL          (1<<4)
#define OBJC_TYPE_BYCOPY_QUAL       (1<<5)
#define OBJC_TYPE_BYREF_QUAL        (1<<6)
#define OBJC_TYPE_ONEWAY_QUAL       (1<<7)

#define OBJC_TYPE_ID_NAME           "id"
#define OBJC_TYPE_CLASS_NAME        "Class"
#define OBJC_TYPE_SEL_NAME          "SEL"

#define OBJC_TYPE_CHAR_CODE         'c'
#define OBJC_TYPE_UCHAR_CODE        'C'
#define OBJC_TYPE_SHORT_CODE        's'
#define OBJC_TYPE_USHORT_CODE       'S'
#define OBJC_TYPE_INT_CODE          'i'
#define OBJC_TYPE_UINT_CODE         'I'
#define OBJC_TYPE_LONG_CODE         'l'
#define OBJC_TYPE_ULONG_CODE        'L'
#define OBJC_TYPE_LONGLONG_CODE     'q'
#define OBJC_TYPE_ULONGLONG_CODE    'Q'
#define OBJC_TYPE_FLOAT_CODE        'f'
#define OBJC_TYPE_DOUBLE_CODE       'd'
#define OBJC_TYPE_BOOL_CODE         'B'
#define OBJC_TYPE_VOID_CODE         'v'
#define OBJC_TYPE_STR_CODE          '*'
#define OBJC_TYPE_ID_CODE           '@'
#define OBJC_TYPE_CLASS_CODE        '#'
#define OBJC_TYPE_SEL_CODE          ':'
#define OBJC_TYPE_PTR_CODE          '^'
#define OBJC_TYPE_BITFIELD_CODE     'b'
#define OBJC_TYPE_UNKNOWN_CODE      '?'
#define OBJC_TYPE_CONST_CODE        'r'
#define OBJC_TYPE_IN_CODE           'n'
#define OBJC_TYPE_INOUT_CODE        'N'
#define OBJC_TYPE_OUT_CODE          'o'
#define OBJC_TYPE_BYCOPY_CODE       'O'
#define OBJC_TYPE_BYREF_CODE        'R'
#define OBJC_TYPE_ONEWAY_CODE       'V'

OBJC_EXPORT objc_type_t objc_make_type();
OBJC_EXPORT objc_type_t objc_make_type_from_code(const char *);
OBJC_EXPORT objc_type_t objc_make_type_from_codep(const char **);
OBJC_EXPORT size_t objc_type_get_type_size(objc_type_t);

OBJC_EXPORT objc_type_list_t objc_make_type_list_from_code(const char *);
OBJC_EXPORT objc_type_list_t objc_make_type_list_from_codep(const char **);
OBJC_EXPORT char *objc_type_list_to_full_code(objc_type_list_t);
OBJC_EXPORT objc_str_list_t objc_type_list_to_code_list(objc_type_list_t);
OBJC_EXPORT size_t objc_type_list_get_type_size(objc_type_list_t);

OBJC_EXPORT objc_type_encoding_t objc_make_type_encoding(objc_type_list_t);
OBJC_EXPORT const char *objc_type_encoding_get_code(objc_type_encoding_t, int);
OBJC_EXPORT size_t objc_type_encoding_get_nargs(objc_type_encoding_t);
OBJC_EXPORT size_t objc_type_encoding_get_frame_length(objc_type_encoding_t);
OBJC_EXPORT const char *objc_type_encoding_get_method_return_code(objc_type_encoding_t);
OBJC_EXPORT size_t objc_type_encoding_get_method_return_size(objc_type_encoding_t);

#endif /* SOBJC_COMMONS_TYPE_H */

